package com.sunday.gateway.security.authorization;

import com.sunday.authorization.security.tools.userdetails.UserInfo;
import com.sunday.gateway.security.authentication.JwtAuthenticationConvert;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
import org.springframework.security.web.server.authorization.AuthorizationWebFilter;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

/**
 * token 传递 通过 http head
 * <p>
 * 0 = {ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter@12904}
 * 1 = {HttpHeaderWriterWebFilter@12905}
 * 2 = {ReactorContextWebFilter@12906}
 * 3 = {AuthenticationWebFilter@12907}
 * 4 = {SecurityContextServerWebExchangeWebFilter@12908}
 * 5 = {ServerRequestCacheWebFilter@12909}
 * 6 = {LogoutWebFilter@12910}
 * 7 = {ExceptionTranslationWebFilter@12453}
 * 8 = {AuthorizationWebFilter@12901}
 * 9 = {TokenTransferFilter@12911}
 * <p>
 * jwt 解析核心流程步骤
 * <p>
 * 身份验证Web过滤器
 * org.springframework.security.web.server.authentication.AuthenticationWebFilter#filter(org.springframework.web.server.ServerWebExchange, org.springframework.web.server.WebFilterChain)
 * 服务器承载令牌认证转换器
 * <p>
 * 解析header中的内容
 * token.isEmpty() ? OAuth2AuthenticationException : BearerTokenAuthenticationToken
 * org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter#convert(org.springframework.web.server.ServerWebExchange)
 * org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter#token(org.springframework.http.server.reactive.ServerHttpRequest)
 * Authorization -> ^Bearer (?<token>[a-zA-Z0-9-._~+/]+=*)$  -> header bearer
 * org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter#resolveFromAuthorizationHeader(org.springframework.http.HttpHeaders)
 * 验证token有效性
 * org.springframework.security.web.server.authentication.AuthenticationWebFilter#authenticate(org.springframework.web.server.ServerWebExchange, org.springframework.web.server.WebFilterChain, org.springframework.security.core.Authentication)
 * org.springframework.security.oauth2.server.resource.authentication.JwtReactiveAuthenticationManager#authenticate(org.springframework.security.core.Authentication)
 * jwt 解析
 * org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder#decode(java.lang.String)
 * org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder#decode(com.nimbusds.jwt.JWT)
 * org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder#createClaimsSet(com.nimbusds.jwt.proc.JWTProcessor, com.nimbusds.jwt.JWT, com.nimbusds.jose.proc.SecurityContext)
 * 进行jwt防篡改验证
 * com.nimbusds.jwt.proc.DefaultJWTProcessor#process(com.nimbusds.jwt.JWT, com.nimbusds.jose.proc.SecurityContext)
 * com.nimbusds.jwt.proc.DefaultJWTProcessor#process(com.nimbusds.jwt.SignedJWT, com.nimbusds.jose.proc.SecurityContext)
 * 进行jwt过期时间验证
 * org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder#validateJwt(org.springframework.security.oauth2.jwt.Jwt)
 * org.springframework.security.oauth2.jwt.JwtTimestampValidator#validate(org.springframework.security.oauth2.jwt.Jwt)
 * -> JwtReactiveAuthenticationManager#authenticate(org.springframework.security.core.Authentication)
 * 最终回归到其他的 filter 继续进行判定
 * -> org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter#filter(org.springframework.web.server.ServerWebExchange, org.springframework.web.server.WebFilterChain)
 *
 * @author sunday
 * @see AuthorizationWebFilter
 * @since 2024/9/27
 */
@Slf4j
public class TokenTransferFilter implements WebFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        return ReactiveSecurityContextHolder.getContext()
                .filter((c) -> c.getAuthentication() != null)
                .map(SecurityContext::getAuthentication)
                .cast(JwtAuthenticationToken.class)
//                .doOnNext(token -> {
//                    log.info("{}", token.getToken().getHeaders());
//                    log.info("{}", token.getTokenAttributes());
//                })
                .map(JwtAuthenticationConvert::convert)
                .map(userInfo -> exchange.mutate()
                        .request(builder -> builder.header(UserInfo.HTTP_HEADER_AUTH_TOKEN_INFO, userInfo.toString()))
                        .build())
//                .doOnSuccess((newExchange) -> log.info("Authorization successful : {}", newExchange))
//                .doOnError(AccessDeniedException.class,
//                        (ex) -> log.info("{}", LogMessage.format("Authorization failed: %s", ex.getMessage())))
                .flatMap(newExchange -> chain.filter(newExchange));
    }

}
